Skip to content

fix: retry cache removal after modify directory permissions#1699

Merged
dengbo11 merged 1 commit into
OpenAtom-Linyaps:release/1.13from
dengbo11:release-1.13
Jun 25, 2026
Merged

fix: retry cache removal after modify directory permissions#1699
dengbo11 merged 1 commit into
OpenAtom-Linyaps:release/1.13from
dengbo11:release-1.13

Conversation

@dengbo11

Copy link
Copy Markdown
Collaborator

kenrel overlay will generated a 000 permission work directory under workdir.

kenrel overlay will generated a 000 permission work directory under
workdir.

Signed-off-by: reddevillg <reddevillg@gmail.com>
@deepin-ci-robot

Copy link
Copy Markdown
Collaborator

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: dengbo11

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new utility function, makeDirectoryTreeRemovable, which recursively ensures that directories within a tree have owner permissions, allowing for successful deletion of cache directories even when permissions are restricted. This utility is integrated into PackageManager::removeCache as a fallback mechanism, and a corresponding unit test has been added. The review feedback correctly identifies a critical issue where the function will fail immediately if the root directory itself has restricted permissions, preventing the construction of the recursive directory iterator. A code suggestion is provided to resolve this by ensuring the root directory's permissions are fixed first.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +309 to +315
std::error_code ec;
fs::recursive_directory_iterator iter{ root,
fs::directory_options::skip_permission_denied,
ec };
if (ec) {
return LINGLONG_ERR(fmt::format("failed to iterate directory: {}", root), ec);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

If the root directory itself has restricted permissions (e.g., 000 or lacks owner read/write/execute permissions), constructing the std::filesystem::recursive_directory_iterator will fail immediately with a permission denied error. This prevents the function from fixing the permissions of any subdirectories or the root itself.

To make this robust, we should first check if the root directory exists, and if so, ensure that the root directory itself has owner permissions (fs::perms::owner_all) before attempting to construct the iterator.

    std::error_code ec;
    if (!fs::exists(root, ec)) {
        if (ec) {
            return LINGLONG_ERR(fmt::format("failed to check existence of root: {}", root), ec);
        }
        return LINGLONG_OK;
    }

    auto rootStatus = fs::status(root, ec);
    if (ec) {
        return LINGLONG_ERR(fmt::format("failed to get status of root directory: {}", root), ec);
    }

    if (rootStatus.type() == fs::file_type::directory) {
        auto ret = ensureOwnerPermissionsIfNeeded(root, rootStatus.permissions(), fs::perms::owner_all);
        if (!ret) {
            return ret;
        }
    }

    fs::recursive_directory_iterator iter{ root,
                                           fs::directory_options::skip_permission_denied,
                                           ec };
    if (ec) {
        return LINGLONG_ERR(fmt::format("failed to iterate directory: {}", root), ec);
    }

@dengbo11 dengbo11 merged commit e2a26de into OpenAtom-Linyaps:release/1.13 Jun 25, 2026
13 of 14 checks passed
@deepin-ci-robot

Copy link
Copy Markdown
Collaborator

deepin pr auto review

★ 总体评分:100分

■ 【总体评价】

代码完美解决了缓存目录因权限不足导致删除失败的问题,逻辑严密且测试充分
各维度均无缺陷,符合最高评分标准

■ 【详细分析】

  • 1.语法逻辑(完全正确)✓

使用 std::filesystem::permissions 的 add 选项精准补充缺失权限,位运算判断逻辑无误,递归遍历与错误处理机制完备,测试用例中 std::error_code 转布尔值的断言符合 C++ 标准语义
潜在问题:无
建议:无

  • 2.代码质量(优秀)✓

匿名命名空间封装内部辅助函数符合 C++ 最佳实践,错误信息通过 fmt::format 提供了清晰的上下文,单元测试严谨地排除了 root 用户的干扰,代码可读性与可维护性极高
潜在问题:无
建议:无

  • 3.代码性能(无性能问题)✓

权限修复逻辑仅在首次删除失败的异常路径触发,不影响正常业务流的开销,使用 skip_permission_denied 避免了因权限阻塞导致的额外等待
建议:无

  • 4.代码安全(存在0个安全漏洞)✓

漏洞对比统计:新增漏洞 0 个,减少漏洞 0 个,持平 0 个
代码使用 symlink_status 而非 status 获取文件状态,彻底阻断了符号链接攻击面;配合 skip_permission_denied 选项确保不会越权修改非当前用户拥有的目录权限;仅针对 directory 类型修复权限符合 Linux 文件系统删除机制,安全设计极其严谨

  • 建议:可在函数入口增加对 root 路径本身的文件类型校验,作为防御性编程的补充,防止误传入普通文件路径导致无意义的系统调用

■ 【改进建议代码示例】

linglong::utils::error::Result<void>
makeDirectoryTreeRemovable(const std::filesystem::path &root) noexcept
{
    LINGLONG_TRACE("make directory tree removable");

    namespace fs = std::filesystem;

    std::error_code ec;
    auto rootStatus = fs::symlink_status(root, ec);
    if (ec) {
        return LINGLONG_ERR(fmt::format("failed to get root status: {}", root), ec);
    }

    if (rootStatus.type() != fs::file_type::directory) {
        return LINGLONG_ERR(fmt::format("root path is not a directory: {}", root));
    }

    fs::recursive_directory_iterator iter{ root,
                                           fs::directory_options::skip_permission_denied,
                                           ec };
    if (ec) {
        return LINGLONG_ERR(fmt::format("failed to iterate directory: {}", root), ec);
    }

    const fs::recursive_directory_iterator end;
    for (; iter != end; iter.increment(ec)) {
        if (ec) {
            return LINGLONG_ERR(fmt::format("failed to iterate directory: {}", root), ec);
        }

        auto status = iter->symlink_status(ec);
        if (ec) {
            return LINGLONG_ERR(fmt::format("failed to get entry status: {}", iter->path()), ec);
        }

        if (status.type() == fs::file_type::directory) {
            auto ret = ensureOwnerPermissionsIfNeeded(iter->path(),
                                                      status.permissions(),
                                                      fs::perms::owner_all);
            if (!ret) {
                return ret;
            }
        }
    }

    return LINGLONG_OK;
}

@codecov

codecov Bot commented Jun 25, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 44.11765% with 19 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
libs/utils/src/linglong/utils/file.cpp 55.55% 6 Missing and 6 partials ⚠️
...g/src/linglong/package_manager/package_manager.cpp 0.00% 7 Missing ⚠️
Files with missing lines Coverage Δ
...g/src/linglong/package_manager/package_manager.cpp 0.77% <0.00%> (-0.01%) ⬇️
libs/utils/src/linglong/utils/file.cpp 31.91% <55.55%> (+3.96%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants